package com.durian.base.rxhttp.param

import com.durian.base.rxhttp.RxHttp
import com.durian.base.rxhttp.cache.CacheMode
import com.durian.base.rxhttp.cache.CacheStrategy
import okhttp3.Headers
import okhttp3.Request

/**
 * 说明：RxBaseParam
 * <p/>
 * 作者：Fanly
 * <p/>
 * 类型：Class
 * <p/>
 * 时间：2020/04/24 19:42
 * <p/>
 * 版本：version 1.0
 */
abstract class RxBaseParam<P>(val url: String, val method: Method) : IParam<P> ,IRxHttp{

    companion object {
        fun get(url: String): RxNobodyParam {
            return RxNobodyParam(url, Method.GET)
        }

        fun post(url: String): RxPostParam {
            return RxPostParam(url, Method.POST)
        }

        fun put(url: String): RxPostParam {
            return RxPostParam(url, Method.PUT)
        }

        fun delete(url: String): RxPostParam {
            return RxPostParam(url, Method.DELETE)
        }

        fun patch(url: String): RxPostParam {
            return RxPostParam(url, Method.PATCH)
        }

        fun head(url: String): RxNobodyParam {
            return RxNobodyParam(url, Method.HEAD)
        }
    }

    val headersBuilder by lazy {
        Headers.Builder()
    }
    val requestBuilder by lazy {
        Request.Builder()
    }
    val paramsBuilder by lazy {
        mutableListOf<KeyValuePair>()
    }
    private var _cacheKey = ""
    private val excludeCacheKeyList by lazy { mutableListOf<String>() }
    var isAssemblyEnable = true
    private val cacheStrategy by lazy { RxHttp.getCacheStrategy() }
    var cancelTag = ""

    private fun buildCacheKey(): String {
        if (_cacheKey.isNullOrEmpty()){
            return StringBuilder(RxHttp.getHttpUrl(url)).also { sb->
                paramsBuilder.forEach {
                    if (!excludeCacheKeyList.contains(it.key)){
                        sb.append(it.key).append(it.value)
                    }
                }
            }.toString()
        }
        return _cacheKey
    }

    override fun excludeCacheKey(vararg keys: String): P {
        keys.forEach {
            if (it.isNotEmpty()){
                excludeCacheKeyList.add(it)
            }
        }
        return this as P
    }

    override fun cacheKey(key:String): P {
        _cacheKey = key
        return this as P
    }

    override fun onlyCache(cacheValidTimeMillis: Int): P {
        cacheStrategy.cacheMode = CacheMode.ONLY_CACHE
        cacheStrategy.cacheValidTimeMillis = if (cacheValidTimeMillis <= 0){ -1 }else{ cacheValidTimeMillis }
        return this as P
    }

    override fun onlyNetwork(): P {
        cacheStrategy.cacheMode = CacheMode.ONLY_NETWORK
        return this as P
    }

    override fun useCache(cacheValidTimeMillis: Int): P {
        cacheStrategy.cacheMode = CacheMode.REQUEST_NETWORK_FAILED_READ_CACHE
        cacheStrategy.cacheValidTimeMillis = if (cacheValidTimeMillis <= 0){ -1 }else{ cacheValidTimeMillis }
        return this as P
    }

    override fun buildCacheStrategy(): CacheStrategy {
        return cacheStrategy.also {
            it.cacheKey = buildCacheKey()
        }
    }

    override fun setAssemblyEnable(enable: Boolean): P {
        isAssemblyEnable = enable
        return this as P
    }

    override fun getHeaders(): Headers {
        return headersBuilder.build()
    }

    override fun getHeader(key: String): String? {
        return headersBuilder[key]
    }

    override fun addHeader(key: String, value: String): P {
        headersBuilder.add(key, value)
        return this as P
    }

    override fun addHeader(line: String): P {
        val index = line.indexOf(":")
        if (index > 1){
            headersBuilder.add(line)
        }
        return this as P
    }

    override fun addHeader(map: Map<String, String>): P {
        map.forEach {
            headersBuilder.add(it.key, it.value)
        }
        return this as P
    }

    override fun setHeader(key: String, value: String): P {
        headersBuilder[key] = value
        return this as P
    }

    override fun removeHeader(key: String): P {
        headersBuilder.removeAll(key)
        return this as P
    }

    override fun addParam(key: String, value: Any, isEncoded: Boolean): P {
        paramsBuilder.add(KeyValuePair(key, value, isEncoded))
        return this as P
    }

    override fun addParam(map: Map<String, Any>): P {
        map.forEach {
            addParam(it.key, it.value)
        }
        return this as P
    }

    override fun removeParam(key: String): P {
        paramsBuilder.remove(KeyValuePair(key, null))
        return this as P
    }

    override fun tag(tag: String): P {
        cancelTag = tag
        return this as P
    }

}